from django.utils.translation import ugettext_lazy as _
try:
	from django.contrib.gis.db import models
except ImportError:
	from django.db import models

import libxml2

__all__ = ["OpenSearch", "DefaultSearch"]

class OpenSearch(object):
	def __init__(self, **config):
		self.config = {
			"InputEncoding" : "UTF-8",
			"OutputEncoding" : "UTF-8",
			"Url" : {
				"type" : "application/xhtml+html",
				"template" : "/duetopia/%(app)s/%(model)s/?%(spec)s",
				}
			}
		self.config.update(config)
		self.model = None
		
	def contribute_to_class(self, cls, name):
		if hasattr(cls, name):
			attr = getattr(cls, name)
			if isinstance(attr, OpenSearch):
				self.update(attr)
		setattr(cls, name, self)
		if not hasattr(cls._meta, "search") or not getattr(cls._meta, "search"):
			setattr(cls._meta, "search", self)
		self.model = cls
		
	def update(self, other):
		config = other.config.copy()
		config.update(self.config)
		self.config = config
		
	@property
	def description(self):
		doc = libxml2.newDoc("1.1")
		
		osd = libxml2.newNode("OpenSearchDescription")
		osns = osd.newNs("http://a9.com/-/spec/opensearch/1.1/", None)
		osd.setNs(osns)
		doc.addChild(osd)

		shortName = self.config.get("ShortName",
					    _("Duetopia %(name)s Search") %
					    {"name" : unicode(self.model._meta.verbose_name)})
		osd.newChild(None, "ShortName", unicode(shortName))

		description = self.config.get("Description",
					      _("Search Duetopia for geospatial data"))
		osd.newChild(None, "Description", unicode(description))

		### optional tags that can appear zero or one time and cannot be
		### determined automatically
		for optional_tag in ["Contact", "LongName", "Developer", "Attribution",
				     "SyndicationRight", "AdultContent"]:
			tag = self.config.get(optional_tag, None)
			if tag:
				osd.newChild(None, optional_tag, unicode(tag))
				
		### optional tags that can appear zero or more times and cannot be
		### determined automatically
		for optional_tag in ["Language", "InputEncoding", "OutputEncoding"]:
			tags = self.config.get(optional_tag, None)
			if tags and not isinstance(tags, list) and not isinstance(tags, tuple):
				tags = [tags]
			if tags:
				for tag in tags:
					osd.newChild(None, optional_tag, unicode(tag))

		search_spec = []
		### figure out what the object's admin search parameters support
		if self.model._meta.admin and self.model._meta.admin.search_fields:
			search_spec.append("q={searchTerms?}")
		for f in self.model._meta.fields:
			if isinstance(f, models.CharField) or \
					isinstance(f, models.EmailField) or \
					isinstance(f, models.IPAddressField) or \
					isinstance(f, models.PhoneNumberField) or \
					isinstance(f, models.SlugField) or \
					isinstance(f, models.TextField) or \
					isinstance(f, models.URLField):
				search_spec.append("%s={searchTerms?}" % (f.name,))
			if isinstance(f, models.IntegerField) or \
					isinstance(f, models.DecimalField) or \
					isinstance(f, models.FloatField) or \
					isinstance(f, models.PositiveIntegerField) or \
					isinstance(f, models.SmallIntegerField):
				search_spec.append("%s={searchTerms?}" % (f.name,))
			if isinstance(f, models.DateField) or \
					isinstance(f, models.DateTimeField):
				search_spec.append("%s={searchTerms?}" % (f.name,))
		search_spec = "&".join(search_spec)

		urls = self.config.get("Url")
		if not isinstance(urls, list) and not isinstance(urls, tuple):
			urls = [urls]
		for u in urls:
			url = osd.newChild(None, "Url", None)
			url.setProp("type", u["type"])
			url.setProp("template",
				    u["template"] % {
					"app" : self.model._meta.app_label,
					"model" : self.model._meta.module_name,
					"spec" : search_spec,
					})

		contact = self.config.get("Contact")
		data = doc.serialize("utf-8", True)
		doc.freeDoc()
		return data

def DefaultSearch(model):
	if hasattr(model._meta, "search"):
		return getattr(model._meta, "search")
